#!/usr/bin/lua
require("apm_core")
require("ApmXml")

local G_DEBUG = false

if G_DEBUG == false then
    function logDebug(fmt,...) end
    function logInfo(fmt,...) end
    function logWarn(fmt,...) end
    function logError(fmt,...) end
    function logFatal(fmt,...) end
end

--- 检测是否属于CNAPS2协议
-- return
-- true; false
local function cnaps2_detect(s_payload)
    if s_payload == nil then return false end
    local s_begin_flag = string.sub(s_payload, 1, 3)           -- 起始标识
    local s_end_flag = string.sub(s_payload, 130, 132)         -- 结束标识
    return s_begin_flag == "{H:" and s_end_flag == "}\r\n"
end

--- 解析报文头
-- return
-- 剩余的报文内容, struct_type, mesg_type, s_mesg_id, s_mesg_ref_id
local function cnaps2_unpack_header(ApmData, s_payload)
    --[[
    local s_version_id = string.sub(s_payload, 4, 5)           -- 版本号(固定填写02)
    local s_orig_sender = string.sub(s_payload, 6, 19)         -- 报文发起人
    local s_orig_sender_sid = string.sub(s_payload, 20, 23)    -- 发送系统号
    local s_orig_receiver = string.sub(s_payload, 24, 37)     -- 报文接收人
    local s_orig_receiver_sid = string.sub(s_payload, 38, 41)  -- 接收系统号
    local s_orig_send_date = string.sub(s_payload, 42, 49)     -- 报文发起日期
    local s_orig_send_time = string.sub(s_payload, 50, 55)     -- 报文发起时间
    --]]
    local s_struct_type = string.sub(s_payload, 56, 58)        -- 格式类型(一代：PKG/CMT；二代：XML)
    local s_mesg_type = string.sub(s_payload, 59, 78)          -- 报文类型代码
    local s_mesg_id = string.sub(s_payload, 79, 98)            -- 通信级标识号
    local s_mesg_ref_id = string.sub(s_payload, 99, 118)       -- 通信级参考号
    --[[
    local s_mesg_priority = string.sub(s_payload, 119, 119)    -- 报文优先级(1：特急；2：紧急；3：普通)
    local s_mesg_direction = string.sub(s_payload, 120, 120)   -- 报文传输方向(由行内发出：U；由NPC发出：D)
    --]]

--    logInfo("mesg_id:[%s] mesg_ref_id:[%s]", s_mesg_id, s_mesg_ref_id)

--    local s_sid = string.upper(s_orig_sender_sid) == string.upper(s_orig_receiver_sid) and string.upper(s_orig_sender_sid) or nil

    return string.sub(s_payload, 133), string.upper(s_struct_type), string.trim(s_mesg_type), string.trim(s_mesg_id), string.trim(s_mesg_ref_id)
end

--- 解析数字签名域
-- return
-- 剩余的报文内容
local function cnaps2_unpack_digital_signature(s_payload)
    local s_begin_flag = string.sub(s_payload, 1, 3)
    local i_index_end_flag
    if s_begin_flag == "{S:" then
        i_index_end_flag, _ = string.find(s_payload, "}\r\n")
        if i_index_end_flag ~= nil then
            return string.sub(s_payload, i_index_end_flag + 3)
        end
    end
    return s_payload
end

--- 解析报文体
-- return
-- true: 解析成功; false: 解析失败
local function cnaps2_unpack_body(ApmData, s_payload, s_mesg_type, s_mesg_id, s_mesg_ref_id)
    if s_payload == nil or
       s_payload == "" or
       s_mesg_type == nil or
       s_mesg_type == ""
    then
        return false
    end

    local t_xml_tree = ApmXml.load(s_payload)
    if t_xml_tree == nil then return false end

--    logDebug("s_mesg_type:[%s]", s_mesg_type);
--    logInfo("s_payload:[%s]", s_payload);

--    ApmData.replaceField("transaction.code", s_mesg_id .. "-" .. s_mesg_ref_id)        -- 添加交易跟踪码
    ApmData.setL7Proto(50011)
    ApmData.replaceField("request.cnaps2.mesg_id", s_mesg_id)
    ApmData.replaceField("request.cnaps2.mesg_ref_id", s_mesg_ref_id)
    ApmData.replaceField("transaction.title", s_mesg_type)

    local s_text
    local s_resp_code = "response.code"
    local s_resp_codestring = "response.code_string"

    -- 业务应答信息组件
    s_text = ApmXml.getValue(t_xml_tree, ".//RspnInf/RjctCd/text()")
    if s_text ~= nil then
        logInfo(".//RspnInf/RjctCd/text():[%s]", s_text)
        ApmData.replaceField(s_resp_code, s_text)
    end
    s_text = ApmXml.getValue(t_xml_tree, ".//RspnInf/RjctInf/text()")
    if s_text ~= nil then
        logInfo(".//RspnInf/RjctInf/text():[%s]", s_text)
        ApmData.replaceField(s_resp_codestring, s_text)
    end

    -- NPC处理信息组件
    s_text = ApmXml.getValue(t_xml_tree, ".//NPCPrcInf/PrcCd/text()")
    if s_text ~= nil then
        logInfo(".//NPCPrcInf/PrcCd/text():[%s]", s_text)
        ApmData.replaceField(s_resp_code, s_text)
    end
    s_text = ApmXml.getValue(t_xml_tree, ".//NPCPrcInf/RjctInf/text()")
    if s_text ~= nil then
        logInfo(".//NPCPrcInf/RjctInf/text():[%s]", s_text)
        ApmData.replaceField(s_resp_codestring, s_text)
    end

    -- 登录/退出应答报文
    s_text = ApmXml.getValue(t_xml_tree, ".//LoginRspnInf/PrcCd/text()")
    if s_text ~= nil then
        logInfo(".//LoginRspnInf/PrcCd/text():[%s]", s_text)
        ApmData.replaceField(s_resp_code, s_text)
    end
    s_text = ApmXml.getValue(t_xml_tree, ".//LoginRspnInf/RjctInf/text()")
    if s_text ~= nil then
        logInfo(".//LoginRspnInf/RjctInf/text():[%s]", s_text)
        ApmData.replaceField(s_resp_codestring, s_text)
    end

    -- 通用处理确认报文
    s_text = ApmXml.getValue(t_xml_tree, ".//CmonConfInf/PrcCd/text()")
    if s_text ~= nil then
        logInfo(".//CmonConfInf/PrcCd/text():[%s]", s_text)
        ApmData.replaceField(s_resp_code, s_text)
    end
    s_text = ApmXml.getValue(t_xml_tree, ".//CmonConfInf/RjctInf/text()")
    if s_text ~= nil then
        logInfo(".//CmonConfInf/RjctInf/text():[%s]", s_text)
        ApmData.replaceField(s_resp_codestring, s_text)
    end

    -- 报文丢弃通知报文
    s_text = ApmXml.getValue(t_xml_tree, ".//DscrdInf/PrcCd/text()")
    if s_text ~= nil then
        logInfo(".//DscrdInf/PrcCd/text():[%s]", s_text)
        ApmData.replaceField(s_resp_code, s_text)
    end
    s_text = ApmXml.getValue(t_xml_tree, ".//DscrdInf/RjctInf/text()")
    if s_text ~= nil then
        logInfo(".//DscrdInf/RjctInf/text():[%s]", s_text)
        ApmData.replaceField(s_resp_codestring, s_text)
    end

    -- 通信级确认报文
    s_text = ApmXml.getValue(t_xml_tree, ".//ConfInf/MsgPrcCd/text()")
    if s_text ~= nil then
        logInfo(".//ConfInf/MsgPrcCd/text():[%s]", s_text)
        ApmData.replaceField(s_resp_code, s_text)
    end

    return true;
end

--- 二代支付协议解析入口函数
-- return 1: 该数据不上报;其它:上报数据
function post_analysis()
    local ApmData = require("ApmData")
    -- 父协议不是ibmmq的退出
    if ApmData.getL7Proto() ~= 1414 then return end

    local s_mq_message, s_struct_type, s_mesg_type, s_mesg_id, s_mesg_ref_id
    local s_em_type = ApmData.getMsgType()
    if s_em_type == nil then
        return
    end

    if s_em_type == 0 then -- 请求
        s_mq_message = ApmData.getField("request.mq.message.text", 1)
        if cnaps2_detect(s_mq_message) then
            s_mq_message, s_struct_type, s_mesg_type, s_mesg_id, s_mesg_ref_id = cnaps2_unpack_header(ApmData, s_mq_message)
            if s_struct_type == "XML" and s_mesg_type ~= nil and s_mesg_id ~= nil and s_mesg_ref_id ~= nil then
                s_mq_message = cnaps2_unpack_digital_signature(s_mq_message)
                cnaps2_unpack_body(ApmData, s_mq_message, s_mesg_type, s_mesg_id, s_mesg_ref_id)
                ApmData.delFields("request.mq.message.text")
            end
        end
    elseif s_em_type == 1 then -- 响应
        s_mq_message = ApmData.getField("response.mq.message.text", 1)
        if cnaps2_detect(s_mq_message) then
            s_mq_message, s_struct_type, s_mesg_type, s_mesg_id, s_mesg_ref_id = cnaps2_unpack_header(ApmData, s_mq_message)
            if s_struct_type == "XML" and s_mesg_type ~= nil and s_mesg_id ~= nil and s_mesg_ref_id ~= nil then
                s_mq_message = cnaps2_unpack_digital_signature(s_mq_message)
                cnaps2_unpack_body(ApmData, s_mq_message, s_mesg_type, s_mesg_id, s_mesg_ref_id)
                ApmData.delFields("request.mq.message.text")
            end
        end
    end

    return
end
